//module;
// #include <concepts>
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <tuple>
#include "../libflow_global.h"
//export module libflow.rangefor;
/*export */namespace flow
{

// template<std::integral I = int>
template <typename I = int>
class range_iterator
{
public:
    range_iterator(I value, I step)
        : value_{value}
        , step_{step}
    { }
    range_iterator& operator++()
    {
        value_ += step_;
        return *this;
    }
    bool operator!=(const range_iterator& other) { return value_ < other.value_; }
    I& operator*() { return value_; }

private:
    I value_, step_;
};

// template<std::integral I = int>
template <typename I = int>
class range
{
public:
    explicit range(I stop)
        : start_{0}
        , stop_{stop}
        , step_{1}
    { }
    range(I start, I stop, I step = 1)
        : start_{start}
        , stop_{stop}
        , step_{step}
    { }
    range_iterator<I> begin() { return range_iterator<I>(start_, step_); }
    range_iterator<I> end() { return range_iterator<I>(stop_, step_); }

private:
    I start_, stop_, step_;
};

// Python-Like enumerate() In C++17
// http://reedbeta.com/blog/python-like-enumerate-in-cpp17/
template <typename T, typename TIter = decltype(std::begin(std::declval<T>())), typename = decltype(std::end(std::declval<T>()))>
constexpr auto enumerate(T&& iterable)
{
    struct iterator
    {
        int i;
        TIter iter;
        bool operator!=(const iterator& other) const { return iter != other.iter; }
        void operator++()
        {
            ++i;
            ++iter;
        }
        auto operator*() const { return std::tie(i, *iter); }
    };
    struct iterable_wrapper
    {
        T iterable;
        auto begin() { return iterator{0, std::begin(iterable)}; }
        auto end() { return iterator{0, std::end(iterable)}; }
    };
    // return iterable_wrapper{ iterable }; // this makes a copy if iterable is a rvalue.
    return iterable_wrapper{std::forward<T>(iterable)};
}

} // namespace flow
  // int main()
  //{
  //   for (auto i : range(10))
  //     std::cout << i << " ";
  //   std::cout << std::endl;
  //
  //   for (auto i : range(1, 10))
  //     std::cout << i << " ";
  //   std::cout << std::endl;
  //
  //   for (auto i : range(1, 100, 5))
  //     std::cout << i << " ";
  //   std::cout << std::endl;
  // }

//
/*struct A {
  int val;
  A(int val) : val(val) { std::cout << "A(int)" << std::endl; }
  A(const A& a) : val(a.val) { cout << "A(A&)" << endl; }
  A(A&& a) : val(a.val) { cout << "A(A&&)" << endl; }
  };*/
// int main(int argc, char** argv)
//{
//   vector<int> arr{ 1, 2, 4 };
//
//   for (size_t i = 0; i < arr.size(); ++i)
//     cout << i << " " << arr[i] << endl;
//
//   size_t idx = 0;
//   for (int v : arr)
//     cout << idx++ << " " << v << endl;
//
//   for (auto it = begin(arr); it != end(arr); ++it)
//     cout << distance(begin(arr), it) << " " << *it << endl;
//
//
//   for (const auto& [i, v] : enumerate(arr))
//     cout << i << " " << v << endl;
//
//   list<string> lst{ "hello", "world!" };
//
//   for (const auto& [i, v] : enumerate(lst))
//     cout << i << " " << v << endl;
//
//   for (const auto& [i, v] : enumerate(string("abcde")))
//     cout << i << " " << v << endl;
//
//   vector<A> vec;
//   vec.reserve(3);
//   vec.emplace_back(1);
//   vec.emplace_back(2);
//   vec.emplace_back(4);
//
//   for (const auto& [i, v] : enumerate(vec))
//     cout << i << " " << v.val << endl;
//
//   for (const auto& [i, v] : enumerate(vector<A>{A(1), A(2), A(4)}))
//     cout << i << " " << v.val << endl;
//
//   return 0;
// }